package designpattern.myproxy;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class LINProxy {
    private static String ln = "\r\n";

    public static Object newProxyInstance(LINClassLoader linClassLoader, Class<?>[] interfaces, LINInvocationHandler h) throws Exception {
        String src = generateSrc(interfaces); //构建一个.java文件
        String filePath = LINProxy.class.getResource("").getPath();
        System.out.println(filePath);
        File f = new File(filePath + "$Proxy0.java");
        try {
            FileWriter fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
        Iterable iterable = manager.getJavaFileObjects(f);
        JavaCompiler.CompilationTask task = compiler.getTask(null, null, null, null, null, iterable);
        task.call();
        try {
            manager.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Class $Proxy0 = linClassLoader.findClass("$Proxy0");
        Constructor<?> constructor = $Proxy0.getConstructor(LINInvocationHandler.class);
        return constructor.newInstance(h);
    }

    private static String generateSrc(Class<?>[] interfaces) {

        StringBuffer sb = new StringBuffer();
        sb.append("package designpattern.myproxy;" + ln);
        sb.append("import designpattern.myproxy.BussinessInterface;" + ln);
        sb.append("import java.lang.reflect.Method;" +ln);
        sb.append("public  class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
        sb.append("LINInvocationHandler h;" + ln);
        sb.append("public $Proxy0(LINInvocationHandler h) throws Exception{" + ln);
            sb.append("this.h=h;");
        sb.append("}" + ln);
        for (Class<?> anInterface : interfaces) {
            for (Method m : anInterface.getMethods()) {
                sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln);
                sb.append("try{" + ln);
                sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{});" + ln);
                sb.append("this.h.invoke(this,m,null);");
                sb.append("}catch(Throwable e){" + ln);
                sb.append("e.printStackTrace();" + ln);
                sb.append("}" +ln);
                sb.append("}" + ln);
            }
            sb.append("}" +ln);
        }

        return sb.toString();
    }
}
